<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.9.0">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    
    <title>
        Java 面试题系列篇-JSP和servlet |
        
        Darklovy</title>
    <meta name="description" content>
    <meta name="keywords" content>
    <meta name="HandheldFriendly" content="True">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <link rel="shortcut icon" href="/">
    <link rel="alternate" href="/atom.xml" title="Darklovy">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="description" content="JSP 和 Servlet什么是JSP页面？JSP页面是一种包含了静态数据和JSP元素两种类型的文本的文本文档。静态数据可以用任何基于文本的格式来表示，比如：HTML或者XML。JSP是一种混合了静态内容和动态产生的内容的技术。这里看下JSP的例子。 JSP请求是如何被处理的？浏览器首先要请求一个以.jsp扩展名结尾的页面，发起JSP请求，然后，Web服务器读取这个请求，使用JSP编译器把JSP页">
<meta name="keywords" content="Java">
<meta property="og:type" content="article">
<meta property="og:title" content="Java 面试题系列篇-JSP和servlet">
<meta property="og:url" content="https://www.ttxxly.top/2018/10/20/Java-面试题系列篇-JSP和servlet/index.html">
<meta property="og:site_name" content="Darklovy">
<meta property="og:description" content="JSP 和 Servlet什么是JSP页面？JSP页面是一种包含了静态数据和JSP元素两种类型的文本的文本文档。静态数据可以用任何基于文本的格式来表示，比如：HTML或者XML。JSP是一种混合了静态内容和动态产生的内容的技术。这里看下JSP的例子。 JSP请求是如何被处理的？浏览器首先要请求一个以.jsp扩展名结尾的页面，发起JSP请求，然后，Web服务器读取这个请求，使用JSP编译器把JSP页">
<meta property="og:locale" content="en">
<meta property="og:updated_time" content="2018-12-25T07:27:58.297Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Java 面试题系列篇-JSP和servlet">
<meta name="twitter:description" content="JSP 和 Servlet什么是JSP页面？JSP页面是一种包含了静态数据和JSP元素两种类型的文本的文本文档。静态数据可以用任何基于文本的格式来表示，比如：HTML或者XML。JSP是一种混合了静态内容和动态产生的内容的技术。这里看下JSP的例子。 JSP请求是如何被处理的？浏览器首先要请求一个以.jsp扩展名结尾的页面，发起JSP请求，然后，Web服务器读取这个请求，使用JSP编译器把JSP页">

    <link href="https://fonts.googleapis.com/css?family=Inconsolata|Titillium+Web" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
    <link href="//cdn.bootcss.com/node-waves/0.7.5/waves.min.css" rel="stylesheet">
    <link rel="stylesheet" href="/style.css">
    <script>
        function setLoadingBarProgress(num) {
            document.getElementById('loading-bar').style.width = num + "%";
        }
    </script>
</head>
</html>
<body>
  <div id="loading-bar-wrapper">
  <div id="loading-bar"></div>
</div>


  <script>setLoadingBarProgress(20)</script> 
  <header class="l_header">
	<div class='wrapper'>
		<div class="nav-main container container--flex">
			<a class="logo flat-box" href='/' >
				Darklovy
			</a>
			<div class='menu'>
				<ul class='h-list'>
					
						<li>
							<a class='flat-box nav-Home' href='/'>
								首页
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-archives' href='/archives'>
								归档
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-categories' href='/categories'>
								分类
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-tags' href='/tags'>
								标签
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-algorithm' href='https://book.algorithm.ttxxly.top/'>
								算法
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-python' href='https://book.python.ttxxly.top/'>
								python
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-about' href='/about'>
								关于
							</a>
						</li>
					
				</ul>
				<div class='underline'></div>
			</div>
			
				<div class="m_search">
					<form name="searchform" class="form u-search-form">
						<input type="text" class="input u-search-input" placeholder="Search" />
						<span class="icon icon-search"></span>
					</form>
				</div>
			
			<ul class='switcher h-list'>
				
					<li class='s-search'><a href='javascript:void(0)'><span class="icon icon-search flat-box"></span></a></li>
				
				<li class='s-menu'><a href='javascript:void(0)'><span class="icon icon-menu flat-box"></span></a></li>
			</ul>
		</div>
		
		<div class='nav-sub container container--flex'>
			<a class="logo" class="flat-box" href='javascript:void(0)'>
				Word of Forks
			</a>

			<ul class='switcher h-list'>
				<li class='s-comment'><a href='javascript:void(0)'><span class="icon icon-chat_bubble_outline flat-box"></span></a></li>
				<li class='s-top'><a href='javascript:void(0)'><span class="icon icon-arrow_upward flat-box"></span></a></li>
				<li class='s-toc'><a href='javascript:void(0)'><span class="icon icon-format_list_numbered flat-box"></span></a></li>
			</ul>
		</div>
	</div>
</header>
<aside class="menu-phone">
	<nav>
		
			<a href="/" class="nav-Home nav">
				首页
			</a>
		
			<a href="/archives" class="nav-archives nav">
				归档
			</a>
		
			<a href="/categories" class="nav-categories nav">
				分类
			</a>
		
			<a href="/tags" class="nav-tags nav">
				标签
			</a>
		
			<a href="https://book.algorithm.ttxxly.top/" class="nav-algorithm nav">
				算法
			</a>
		
			<a href="https://book.python.ttxxly.top/" class="nav-python nav">
				python
			</a>
		
			<a href="/about" class="nav-about nav">
				关于
			</a>
		
	</nav>
</aside>

    <script>setLoadingBarProgress(40);</script>
  <div class="l_body">
    <div class='container clearfix'>
      <div class='l_main'>
        <article id="post-Java-面试题系列篇-JSP和servlet"
  class="post white-box article-type-post"
  itemscope itemprop="blogPost">
	<section class='meta'>
	<h2 class="title">
  	<a href="/2018/10/20/Java-面试题系列篇-JSP和servlet/">
    	Java 面试题系列篇-JSP和servlet
    </a>
  </h2>
	<time>
	  Oct 20, 2018
	</time>
	
	</section>
	
		<section class="toc-wrapper"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#JSP-和-Servlet"><span class="toc-number">1.</span> <span class="toc-text">JSP 和 Servlet</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是JSP页面？"><span class="toc-number">1.1.</span> <span class="toc-text">什么是JSP页面？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JSP请求是如何被处理的？"><span class="toc-number">1.2.</span> <span class="toc-text">JSP请求是如何被处理的？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JSP有哪些内置对象？作用分别是什么？"><span class="toc-number">1.3.</span> <span class="toc-text">JSP有哪些内置对象？作用分别是什么？</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#null"><span class="toc-number"></span> <span class="toc-text">Hello, World!</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#null"><span class="toc-number">1.</span> <span class="toc-text">Current time is: &lt;%= new java.util.Date().toString() %&gt;</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#null"><span class="toc-number"></span> <span class="toc-text">Hello, World!</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#null"><span class="toc-number">1.</span> <span class="toc-text">Current time is: “);
​            out.print(new java.util.Date().toString());
​            out.write(“</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#JSP有什么优点？"><span class="toc-number">1.1.</span> <span class="toc-text">JSP有什么优点？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是JSP指令-Directive-？JSP中有哪些不同类型的指令？"><span class="toc-number">1.2.</span> <span class="toc-text">什么是JSP指令(Directive)？JSP中有哪些不同类型的指令？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是JSP动作-JSP-action-？"><span class="toc-number">1.3.</span> <span class="toc-text">什么是JSP动作(JSP action)？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是Scriptlets？"><span class="toc-number">1.4.</span> <span class="toc-text">什么是Scriptlets？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#get和post请求的区别？"><span class="toc-number">1.5.</span> <span class="toc-text">get和post请求的区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#声明-Decalaration-在哪里？"><span class="toc-number">1.6.</span> <span class="toc-text">声明(Decalaration)在哪里？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是表达式-Expression-？"><span class="toc-number">1.7.</span> <span class="toc-text">什么是表达式(Expression)？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#隐含对象是什么意思？有哪些隐含对象？"><span class="toc-number">1.8.</span> <span class="toc-text">隐含对象是什么意思？有哪些隐含对象？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JSP和Servlet是什么关系？"><span class="toc-number">1.9.</span> <span class="toc-text">JSP和Servlet是什么关系？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#常用的Web服务器有哪些？"><span class="toc-number">1.10.</span> <span class="toc-text">常用的Web服务器有哪些？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#如何实现JSP或Servlet的单线程模式？"><span class="toc-number">1.11.</span> <span class="toc-text">如何实现JSP或Servlet的单线程模式？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#实现会话跟踪的技术有哪些？"><span class="toc-number">1.12.</span> <span class="toc-text">实现会话跟踪的技术有哪些？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#过滤器有哪些作用和用法？"><span class="toc-number">1.13.</span> <span class="toc-text">过滤器有哪些作用和用法？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#监听器有哪些作用和用法？"><span class="toc-number">1.14.</span> <span class="toc-text">监听器有哪些作用和用法？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#web-xml文件中可以配置哪些内容？"><span class="toc-number">1.15.</span> <span class="toc-text">web.xml文件中可以配置哪些内容？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#你的项目中使用过哪些JSTL标签？"><span class="toc-number">1.16.</span> <span class="toc-text">你的项目中使用过哪些JSTL标签？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用标签库有什么好处？如何自定义JSP标签？"><span class="toc-number">1.17.</span> <span class="toc-text">使用标签库有什么好处？如何自定义JSP标签？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#说一下表达式语言（EL）的隐式对象及其作用。"><span class="toc-number">1.18.</span> <span class="toc-text">说一下表达式语言（EL）的隐式对象及其作用。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#表达式语言（EL）支持哪些运算符？"><span class="toc-number">1.19.</span> <span class="toc-text">表达式语言（EL）支持哪些运算符？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Java-Web开发的Model-1和Model-2分别指的是什么？"><span class="toc-number">1.20.</span> <span class="toc-text">Java Web开发的Model 1和Model 2分别指的是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Servlet-3中的异步处理指的是什么？"><span class="toc-number">1.21.</span> <span class="toc-text">Servlet 3中的异步处理指的是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#讲解JSP中的四种作用域。"><span class="toc-number">1.22.</span> <span class="toc-text">讲解JSP中的四种作用域。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#如何在基于Java的Web项目中实现文件上传和下载？"><span class="toc-number">1.23.</span> <span class="toc-text">如何在基于Java的Web项目中实现文件上传和下载？</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#null"><span class="toc-number"></span> <span class="toc-text">Select your photo and upload</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#服务器收到用户提交的表单数据，到底是调用Servlet的doGet-还是doPost-方法？"><span class="toc-number">0.1.</span> <span class="toc-text">服务器收到用户提交的表单数据，到底是调用Servlet的doGet()还是doPost()方法？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Servlet中如何获取用户提交的查询参数或表单数据？"><span class="toc-number">0.2.</span> <span class="toc-text">Servlet中如何获取用户提交的查询参数或表单数据？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#如何设置请求的编码以及响应内容的类型？"><span class="toc-number">0.3.</span> <span class="toc-text">如何设置请求的编码以及响应内容的类型？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#阐述Servlet和CGI的区别"><span class="toc-number">0.4.</span> <span class="toc-text">阐述Servlet和CGI的区别?</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是Servlet？"><span class="toc-number">0.5.</span> <span class="toc-text">什么是Servlet？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Servlet接口中有哪些方法？"><span class="toc-number">0.6.</span> <span class="toc-text">Servlet接口中有哪些方法？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#说一下Servlet的体系结构。"><span class="toc-number">0.7.</span> <span class="toc-text">说一下Servlet的体系结构。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Applet和Servlet有什么区别？"><span class="toc-number">0.8.</span> <span class="toc-text">Applet和Servlet有什么区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#GenericServlet和HttpServlet有什么区别？"><span class="toc-number">0.9.</span> <span class="toc-text">GenericServlet和HttpServlet有什么区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#解释下Servlet的生命周期。"><span class="toc-number">0.10.</span> <span class="toc-text">解释下Servlet的生命周期。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#doGet-方法和doPost-方法有什么区别？"><span class="toc-number">0.11.</span> <span class="toc-text">doGet()方法和doPost()方法有什么区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是Web应用程序？"><span class="toc-number">0.12.</span> <span class="toc-text">什么是Web应用程序？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是服务端包含-Server-Side-Include-？"><span class="toc-number">0.13.</span> <span class="toc-text">什么是服务端包含(Server Side Include)？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是Servlet链-Servlet-Chaining-？"><span class="toc-number">0.14.</span> <span class="toc-text">什么是Servlet链(Servlet Chaining)？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#如何知道是哪一个客户端的机器正在请求你的Servlet？"><span class="toc-number">0.15.</span> <span class="toc-text">如何知道是哪一个客户端的机器正在请求你的Servlet？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#HTTP响应的结构是怎么样的？"><span class="toc-number">0.16.</span> <span class="toc-text">HTTP响应的结构是怎么样的？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是cookie？session和cookie有什么区别？"><span class="toc-number">0.17.</span> <span class="toc-text">什么是cookie？session和cookie有什么区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#浏览器和Servlet通信使用的是什么协议？"><span class="toc-number">0.18.</span> <span class="toc-text">浏览器和Servlet通信使用的是什么协议？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是HTTP隧道？"><span class="toc-number">0.19.</span> <span class="toc-text">什么是HTTP隧道？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#sendRedirect-和forward-方法有什么区别？"><span class="toc-number">0.20.</span> <span class="toc-text">sendRedirect()和forward()方法有什么区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是URL编码和URL解码？"><span class="toc-number">0.21.</span> <span class="toc-text">什么是URL编码和URL解码？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#转发（forward）和重定向（redirect）的区别？"><span class="toc-number">0.22.</span> <span class="toc-text">转发（forward）和重定向（redirect）的区别？</span></a></li></ol></li></ol></section>
	
	<section class="article typo">
  	<div class="article-entry" itemprop="articleBody">
    	<h2 id="JSP-和-Servlet"><a href="#JSP-和-Servlet" class="headerlink" title="JSP 和 Servlet"></a>JSP 和 Servlet</h2><h3 id="什么是JSP页面？"><a href="#什么是JSP页面？" class="headerlink" title="什么是JSP页面？"></a>什么是JSP页面？</h3><p>JSP页面是一种包含了静态数据和JSP元素两种类型的文本的文本文档。静态数据可以用任何基于文本的格式来表示，比如：HTML或者XML。JSP是一种混合了静态内容和动态产生的内容的技术。这里看下JSP的例子。</p>
<h3 id="JSP请求是如何被处理的？"><a href="#JSP请求是如何被处理的？" class="headerlink" title="JSP请求是如何被处理的？"></a>JSP请求是如何被处理的？</h3><p>浏览器首先要请求一个以.jsp扩展名结尾的页面，发起JSP请求，然后，Web服务器读取这个请求，使用JSP编译器把JSP页面转化成一个Servlet类。需要注意的是，只有当第一次请求页面或者是JSP文件发生改变的时候JSP文件才会被编译，然后服务器调用servlet类，处理浏览器的请求。一旦请求执行结束，servlet会把响应发送给客户端。这里看下如何在JSP中获取请求参数。</p>
<h3 id="JSP有哪些内置对象？作用分别是什么？"><a href="#JSP有哪些内置对象？作用分别是什么？" class="headerlink" title="JSP有哪些内置对象？作用分别是什么？"></a>JSP有哪些内置对象？作用分别是什么？</h3><p>答：JSP有9个内置对象： </p>
<ul>
<li>request：封装客户端的请求，其中包含来自GET或POST请求的参数； </li>
<li>response：封装服务器对客户端的响应； </li>
<li>pageContext：通过该对象可以获取其他对象； </li>
<li>session：封装用户会话的对象； </li>
<li>application：封装服务器运行环境的对象； </li>
<li>out：输出服务器响应的输出流对象； </li>
<li>config：Web应用的配置对象； </li>
<li>page：JSP页面本身（相当于Java程序中的this）； </li>
<li>exception：封装页面抛出异常的对象。</li>
</ul>
<p>补充：如果用Servlet来生成网页中的动态内容无疑是非常繁琐的工作，另一方面，所有的文本和HTML标签都是硬编码，即使做出微小的修改，都需要进行重新编译。JSP解决了Servlet的这些问题，它是Servlet很好的补充，可以专门用作为用户呈现视图（View），而Servlet作为控制器（Controller）专门负责处理用户请求并转发或重定向到某个页面。基于Java的Web开发很多都同时使用了Servlet和JSP。JSP页面其实是一个Servlet，能够运行Servlet的服务器（Servlet容器）通常也是JSP容器，可以提供JSP页面的运行环境，Tomcat就是一个Servlet/JSP容器。第一次请求一个JSP页面时，Servlet/JSP容器首先将JSP页面转换成一个JSP页面的实现类，这是一个实现了JspPage接口或其子接口HttpJspPage的Java类。JspPage接口是Servlet的子接口，因此每个JSP页面都是一个Servlet。转换成功后，容器会编译Servlet类，之后容器加载和实例化Java字节码，并执行它通常对Servlet所做的生命周期操作。对同一个JSP页面的后续请求，容器会查看这个JSP页面是否被修改过，如果修改过就会重新转换并重新编译并执行。如果没有则执行内存中已经存在的Servlet实例。我们可以看一段JSP代码对应的Java程序就知道一切了，而且9个内置对象的神秘面纱也会被揭开。</p>
<p>JSP页面：</p>
<p>&lt;%@ page pageEncoding=”UTF-8”%&gt;</p>
<p>&lt;%</p>
<p>String path = request.getContextPath();</p>
<p>String basePath = request.getScheme() + “://“ + request.getServerName() + “:” + request.getServerPort() + path + “/“;</p>
<p>%&gt;</p>
<p>&lt;!DOCTYPE html&gt;</p>
<html><br><br>  <head><meta name="generator" content="Hexo 3.9.0"><br><br>​    <base href="<%=basePath%>"><br><br>​    <title>首页</title><br><br>    <style type="text/css"><br><br>​        * { font-family: “Arial”; }<br><br>​    </style><br><br>  </head><br><br><br><br>  <body><br><br>​    <h1>Hello, World!</h1><br><br>​    <hr><br><br>​    <h2>Current time is: &lt;%= new java.util.Date().toString() %&gt;</h2><br><br>  </body><br><br></html>

<p>对应的Java代码：</p>
<p>/*</p>
<ul>
<li>Generated by the Jasper component of Apache Tomcat</li>
<li>Version: Apache Tomcat/7.0.52</li>
<li>Generated at: 2014-10-13 13:28:38 UTC</li>
<li>Note: The last modified time of this file was set to</li>
<li>the last modified time of the source file after</li>
<li><p>generation to assist with modification tracking.</p>
<p>*/</p>
</li>
</ul>
<p>package org.apache.jsp;</p>
<p>import javax.servlet.*;</p>
<p>import javax.servlet.http.*;</p>
<p>import javax.servlet.jsp.*;</p>
<p>public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase</p>
<p>​        implements org.apache.jasper.runtime.JspSourceDependent {</p>
<p>​    private static final javax.servlet.jsp.JspFactory _jspxFactory = javax.servlet.jsp.JspFactory</p>
<p>​            .getDefaultFactory();</p>
<p>​    private static java.util.Map&lt;java.lang.String, java.lang.Long&gt; _jspx_dependants;</p>
<p>​    private javax.el.ExpressionFactory _el_expressionfactory;</p>
<p>​    private org.apache.tomcat.InstanceManager _jsp_instancemanager;</p>
<p>​    public java.util.Map&lt;java.lang.String, java.lang.Long&gt; getDependants() {</p>
<p>​        return _jspx_dependants;</p>
<p>​    }</p>
<p>​    public void _jspInit() {</p>
<p>​        _el_expressionfactory = _jspxFactory.getJspApplicationContext(</p>
<p>​                getServletConfig().getServletContext()).getExpressionFactory();</p>
<p>​        _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory</p>
<p>​                .getInstanceManager(getServletConfig());</p>
<p>​    }</p>
<p>​    public void _jspDestroy() {</p>
<p>​    }</p>
<p>​    public void _jspService(</p>
<p>​            final javax.servlet.http.HttpServletRequest request,</p>
<p>​            final javax.servlet.http.HttpServletResponse response)</p>
<p>​            throws java.io.IOException, javax.servlet.ServletException {</p>
<p>​        // 内置对象就是在这里定义的</p>
<p>​        final javax.servlet.jsp.PageContext pageContext;</p>
<p>​        javax.servlet.http.HttpSession session = null;</p>
<p>​        final javax.servlet.ServletContext application;</p>
<p>​        final javax.servlet.ServletConfig config;</p>
<p>​        javax.servlet.jsp.JspWriter out = null;</p>
<p>​        final java.lang.Object page = this;</p>
<p>​        javax.servlet.jsp.JspWriter _jspx_out = null;</p>
<p>​        javax.servlet.jsp.PageContext _jspx_page_context = null;</p>
<p>​        try {</p>
<p>​            response.setContentType(“text/html;charset=UTF-8”);</p>
<p>​            pageContext = _jspxFactory.getPageContext(this, request, response,</p>
<p>​                    null, true, 8192, true);</p>
<p>​            _jspx_page_context = pageContext;</p>
<p>​            application = pageContext.getServletContext();</p>
<p>​            config = pageContext.getServletConfig();</p>
<p>​            session = pageContext.getSession();</p>
<p>​            out = pageContext.getOut();</p>
<p>​            _jspx_out = out;</p>
<p>​            out.write(‘\r’);</p>
<p>​            out.write(‘\n’);</p>
<p>​            String path = request.getContextPath();</p>
<p>​            String basePath = request.getScheme() + “://“</p>
<p>​                    + request.getServerName() + “:” + request.getServerPort()</p>
<p>​                    + path + “/“;</p>
<p>// 以下代码通过输出流将HTML标签输出到浏览器中</p>
<p>​            out.write(“\r\n”);</p>
<p>​            out.write(“\r\n”);</p>
<p>​            out.write(“&lt;!DOCTYPE html&gt;\r\n”);</p>
<p>​            out.write(“<html>\r\n”);</html></p>
<p>​            out.write(“  <head><meta name="generator" content="Hexo 3.9.0">\r\n”);</head></p>
<p>​            out.write(“    &lt;base href=””);</p>
<p>​            out.print(basePath);</p>
<p>​            out.write(“”&gt;\r\n”);</p>
<p>​            out.write(“    <title>首页</title>\r\n”);</p>
<p>​            out.write(“    <style type="text/css">\r\n”);</p>
<p>​            out.write(“    \t* { font-family: “Arial”; }\r\n”);</p>
<p>​            out.write(“    </style>\r\n”);</p>
<p>​            out.write(“  \r\n”);</p>
<p>​            out.write(“  \r\n”);</p>
<p>​            out.write(“  <body>\r\n”);</body></p>
<p>​            out.write(“    </p><h1>Hello, World!</h1>\r\n”);<p></p>
<p>​            out.write(“    <hr>\r\n”);</p>
<p>​            out.write(“    </p><h2>Current time is: “);<p></p>
<p>​            out.print(new java.util.Date().toString());</p>
<p>​            out.write(“</p></h2>\r\n”);<p></p>
<p>​            out.write(“  \r\n”);</p>
<p>​            out.write(“\r\n”);</p>
<p>​        } catch (java.lang.Throwable t) {</p>
<p>​            if (!(t instanceof javax.servlet.jsp.SkipPageException)) {</p>
<p>​                out = _jspx_out;</p>
<p>​                if (out != null &amp;&amp; out.getBufferSize() != 0)</p>
<p>​                    try {</p>
<p>​                        out.clearBuffer();</p>
<p>​                    } catch (java.io.IOException e) {</p>
<p>​                    }</p>
<p>​                if (_jspx_page_context != null)</p>
<p>​                    _jspx_page_context.handlePageException(t);</p>
<p>​                else</p>
<p>​                    throw new ServletException(t);</p>
<p>​            }</p>
<p>​        } finally {</p>
<p>​            jspxFactory.releasePageContext(jspx_page_context);</p>
<p>​        }</p>
<p>​    }</p>
<p>}</p>
<h3 id="JSP有什么优点？"><a href="#JSP有什么优点？" class="headerlink" title="JSP有什么优点？"></a>JSP有什么优点？</h3><p>下面列出了使用JSP的优点：</p>
<p>JSP页面是被动态编译成Servlet的，因此，开发者可以很容易的更新展现代码。</p>
<p>JSP页面可以被预编译。</p>
<p>JSP页面可以很容易的和静态模板结合，包括：HTML或者XML，也可以很容易的和产生动态内容的代码结合起来。</p>
<p>开发者可以提供让页面设计者以类XML格式来访问的自定义的JSP标签库。</p>
<p>开发者可以在组件层做逻辑上的改变，而不需要编辑单独使用了应用层逻辑的页面。</p>
<h3 id="什么是JSP指令-Directive-？JSP中有哪些不同类型的指令？"><a href="#什么是JSP指令-Directive-？JSP中有哪些不同类型的指令？" class="headerlink" title="什么是JSP指令(Directive)？JSP中有哪些不同类型的指令？"></a>什么是JSP指令(Directive)？JSP中有哪些不同类型的指令？</h3><p>Directive是当JSP页面被编译成Servlet的时候，JSP引擎要处理的指令。Directive用来设置页面级别的指令，从外部文件插入数据，指定自定义的标签库。Directive是定义在 &lt;%@ 和 %&gt;之间的。下面列出了不同类型的Directive：</p>
<p>包含指令(Include directive)：用来包含文件和合并文件内容到当前的页面。</p>
<p>页面指令(Page directive)：用来定义JSP页面中特定的属性，比如错误页面和缓冲区。</p>
<p>Taglib指令： 用来声明页面中使用的自定义的标签库。</p>
<h3 id="什么是JSP动作-JSP-action-？"><a href="#什么是JSP动作-JSP-action-？" class="headerlink" title="什么是JSP动作(JSP action)？"></a>什么是JSP动作(JSP action)？</h3><p>JSP动作以XML语法的结构来控制Servlet引擎的行为。当JSP页面被请求的时候，JSP动作会被执行。它们可以被动态的插入到文件中，重用JavaBean组件，转发用户到其他的页面，或者是给Java插件产生HTML代码。下面列出了可用的动作：</p>
<p>jsp:include-当JSP页面被请求的时候包含一个文件。</p>
<p>jsp:useBean-找出或者是初始化Javabean。</p>
<p>jsp:setProperty-设置JavaBean的属性。</p>
<p>jsp:getProperty-获取JavaBean的属性。</p>
<p>jsp:forward-把请求转发到新的页面。</p>
<p>jsp:plugin-产生特定浏览器的代码。</p>
<h3 id="什么是Scriptlets？"><a href="#什么是Scriptlets？" class="headerlink" title="什么是Scriptlets？"></a>什么是Scriptlets？</h3><p>JSP技术中，scriptlet是嵌入在JSP页面中的一段Java代码。scriptlet是位于标签内部的所有的东西，在标签与标签之间，用户可以添加任意有效的scriplet。</p>
<h3 id="get和post请求的区别？"><a href="#get和post请求的区别？" class="headerlink" title="get和post请求的区别？"></a>get和post请求的区别？</h3><p>答： </p>
<p>get请求用来从服务器上获得资源，而post是用来向服务器提交数据； </p>
<p>get将表单中数据按照name=value的形式，添加到action 所指向的URL 后面，并且两者使用”?”连接，而各个变量之间使用”&amp;”连接；post是将表单中的数据放在HTTP协议的请求头或消息体中，传递到action所指向URL； </p>
<p>get传输的数据要受到URL长度限制（1024字节）；而post可以传输大量的数据，上传文件通常要使用post方式； </p>
<p>使用get时参数会显示在地址栏上，如果这些数据不是敏感数据，那么可以使用get；对于敏感数据还是应用使用post； </p>
<p>get使用MIME类型application/x-www-form-urlencoded的URL编码（也叫百分号编码）文本的格式传递参数，保证被传送的参数由遵循规范的文本组成，例如一个空格的编码是”%20”。</p>
<h3 id="声明-Decalaration-在哪里？"><a href="#声明-Decalaration-在哪里？" class="headerlink" title="声明(Decalaration)在哪里？"></a>声明(Decalaration)在哪里？</h3><p>声明跟Java中的变量声明很相似，它用来声明随后要被表达式或者scriptlet使用的变量。添加的声明必须要用开始和结束标签包起来。</p>
<h3 id="什么是表达式-Expression-？"><a href="#什么是表达式-Expression-？" class="headerlink" title="什么是表达式(Expression)？"></a>什么是表达式(Expression)？</h3><p>【列表很长，可以分上、中、下发布】</p>
<p>JSP表达式是Web服务器把脚本语言表达式的值转化成一个String对象，插入到返回给客户端的数据流中。表达式是在&lt;%=和%&gt;这两个标签之间定义的。</p>
<h3 id="隐含对象是什么意思？有哪些隐含对象？"><a href="#隐含对象是什么意思？有哪些隐含对象？" class="headerlink" title="隐含对象是什么意思？有哪些隐含对象？"></a>隐含对象是什么意思？有哪些隐含对象？</h3><p>JSP隐含对象是页面中的一些Java对象，JSP容器让这些Java对象可以为开发者所使用。开发者不用明确的声明就可以直接使用他们。JSP隐含对象也叫做预定义变量。下面列出了JSP页面中的隐含对象：</p>
<p>application</p>
<p>page</p>
<p>request</p>
<p>response</p>
<p>session</p>
<p>exception</p>
<p>out</p>
<p>config</p>
<p>pageContext</p>
<h3 id="JSP和Servlet是什么关系？"><a href="#JSP和Servlet是什么关系？" class="headerlink" title="JSP和Servlet是什么关系？"></a>JSP和Servlet是什么关系？</h3><p>答：其实这个问题在上面已经阐述过了，Servlet是一个特殊的Java程序，它运行于服务器的JVM中，能够依靠服务器的支持向浏览器提供显示内容。JSP本质上是Servlet的一种简易形式，JSP会被服务器处理成一个类似于Servlet的Java程序，可以简化页面内容的生成。Servlet和JSP最主要的不同点在于，Servlet的应用逻辑是在Java文件中，并且完全从表示层中的HTML分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。有人说，Servlet就是在Java中写HTML，而JSP就是在HTML中写Java代码，当然这个说法是很片面且不够准确的。JSP侧重于视图，Servlet更侧重于控制逻辑，在MVC架构模式中，JSP适合充当视图（view）而Servlet适合充当控制器（controller）。</p>
<h3 id="常用的Web服务器有哪些？"><a href="#常用的Web服务器有哪些？" class="headerlink" title="常用的Web服务器有哪些？"></a>常用的Web服务器有哪些？</h3><p>答：Unix和Linux平台下使用最广泛的免费HTTP服务器是Apache服务器，而Windows平台的服务器通常使用IIS作为Web服务器。选择Web服务器应考虑的因素有：性能、安全性、日志和统计、虚拟主机、代理服务器、缓冲服务和集成应用程序等。下面是对常见服务器的简介： </p>
<ul>
<li>IIS：Microsoft的Web服务器产品，全称是Internet Information Services。IIS是允许在公共Intranet或Internet上发布信息的Web服务器。IIS是目前最流行的Web服务器产品之一，很多著名的网站都是建立在IIS的平台上。IIS提供了一个图形界面的管理工具，称为Internet服务管理器，可用于监视配置和控制Internet服务。IIS是一种Web服务组件，其中包括Web服务器、FTP服务器、NNTP服务器和SMTP服务器，分别用于网页浏览、文件传输、新闻服务和邮件发送等方面，它使得在网络（包括互联网和局域网）上发布信息成了一件很容易的事。它提供ISAPI(Intranet Server API）作为扩展Web服务器功能的编程接口；同时，它还提供一个Internet数据库连接器，可以实现对数据库的查询和更新。 </li>
<li>Kangle：Kangle Web服务器是一款跨平台、功能强大、安全稳定、易操作的高性能Web服务器和反向代理服务器软件。此外，Kangle也是一款专为做虚拟主机研发的Web服务器。实现虚拟主机独立进程、独立身份运行。用户之间安全隔离，一个用户出问题不影响其他用户。支持PHP、ASP、ASP.NET、Java、Ruby等多种动态开发语言。 </li>
<li>WebSphere：WebSphere Application Server是功能完善、开放的Web应用程序服务器，是IBM电子商务计划的核心部分，它是基于Java的应用环境，用于建立、部署和管理Internet和Intranet Web应用程序，适应各种Web应用程序服务器的需要。 </li>
<li>WebLogic：WebLogic Server是一款多功能、基于标准的Web应用服务器，为企业构建企业应用提供了坚实的基础。针对各种应用开发、关键性任务的部署，各种系统和数据库的集成、跨Internet协作等Weblogic都提供了相应的支持。由于它具有全面的功能、对开放标准的遵从性、多层架构、支持基于组件的开发等优势，很多公司的企业级应用都选择它来作为开发和部署的环境。WebLogic Server在使应用服务器成为企业应用架构的基础方面一直处于领先地位，为构建集成化的企业级应用提供了稳固的基础。 </li>
<li>Apache：目前Apache仍然是世界上用得最多的Web服务器，其市场占有率很长时间都保持在60%以上（目前的市场份额约40%左右）。世界上很多著名的网站都是Apache的产物，它的成功之处主要在于它的源代码开放、有一支强大的开发团队、支持跨平台的应用（可以运行在几乎所有的Unix、Windows、Linux系统平台上）以及它的可移植性等方面。 </li>
<li>Tomcat：Tomcat是一个开放源代码、运行Servlet和JSP的容器。Tomcat实现了Servlet和JSP规范。此外，Tomcat还实现了Apache-Jakarta规范而且比绝大多数商业应用软件服务器要好，因此目前也有不少的Web服务器都选择了Tomcat。 </li>
<li>Nginx：读作”engine x”，是一个高性能的HTTP和反向代理服务器，也是一个IMAP/POP3/SMTP代理服务器。 Nginx是由Igor Sysoev为俄罗斯访问量第二的Rambler站点开发的，第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布，因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。在2014年下半年，Nginx的市场份额达到了14%。</li>
</ul>
<h3 id="如何实现JSP或Servlet的单线程模式？"><a href="#如何实现JSP或Servlet的单线程模式？" class="headerlink" title="如何实现JSP或Servlet的单线程模式？"></a>如何实现JSP或Servlet的单线程模式？</h3><p>答：<br>对于JSP页面，可以通过page指令进行设置。</p>
<p>&lt;%@page isThreadSafe=”false”%&gt;</p>
<p>1</p>
<p>对于Servlet，可以让自定义的Servlet实现SingleThreadModel标识接口。</p>
<p>说明：如果将JSP或Servlet设置成单线程工作模式，会导致每个请求创建一个Servlet实例，这种实践将导致严重的性能问题（服务器的内存压力很大，还会导致频繁的垃圾回收），所以通常情况下并不会这么做。</p>
<h3 id="实现会话跟踪的技术有哪些？"><a href="#实现会话跟踪的技术有哪些？" class="headerlink" title="实现会话跟踪的技术有哪些？"></a>实现会话跟踪的技术有哪些？</h3><p>答：由于HTTP协议本身是无状态的，服务器为了区分不同的用户，就需要对用户会话进行跟踪，简单的说就是为用户进行登记，为用户分配唯一的ID，下一次用户在请求中包含此ID，服务器据此判断到底是哪一个用户。<br>①URL 重写：在URL中添加用户会话的信息作为请求的参数，或者将唯一的会话ID添加到URL结尾以标识一个会话。<br>②设置表单隐藏域：将和会话跟踪相关的字段添加到隐式表单域中，这些信息不会在浏览器中显示但是提交表单时会提交给服务器。<br>这两种方式很难处理跨越多个页面的信息传递，因为如果每次都要修改URL或在页面中添加隐式表单域来存储用户会话相关信息，事情将变得非常麻烦。<br>③cookie：cookie有两种，一种是基于窗口的，浏览器窗口关闭后，cookie就没有了；另一种是将信息存储在一个临时文件中，并设置存在的时间。当用户通过浏览器和服务器建立一次会话后，会话ID就会随响应信息返回存储在基于窗口的cookie中，那就意味着只要浏览器没有关闭，会话没有超时，下一次请求时这个会话ID又会提交给服务器让服务器识别用户身份。会话中可以为用户保存信息。会话对象是在服务器内存中的，而基于窗口的cookie是在客户端内存中的。如果浏览器禁用了cookie，那么就需要通过下面两种方式进行会话跟踪。当然，在使用cookie时要注意几点：首先不要在cookie中存放敏感信息；其次cookie存储的数据量有限（4k），不能将过多的内容存储cookie中；再者浏览器通常只允许一个站点最多存放20个cookie。当然，和用户会话相关的其他信息（除了会话ID）也可以存在cookie方便进行会话跟踪。<br>④HttpSession：在所有会话跟踪技术中，HttpSession对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动创建HttpSession，每个用户可以访问他自己的HttpSession。可以通过HttpServletRequest对象的getSession方法获得HttpSession，通过HttpSession的setAttribute方法可以将一个值放在HttpSession中，通过调用HttpSession对象的getAttribute方法，同时传入属性名就可以获取保存在HttpSession中的对象。与上面三种方式不同的是，HttpSession放在服务器的内存中，因此不要将过大的对象放在里面，即使目前的Servlet容器可以在内存将满时将HttpSession中的对象移到其他存储设备中，但是这样势必影响性能。添加到HttpSession中的值可以是任意Java对象，这个对象最好实现了Serializable接口，这样Servlet容器在必要的时候可以将其序列化到文件中，否则在序列化时就会出现异常。</p>
<p>补充：HTML5中可以使用Web Storage技术通过JavaScript来保存数据，例如可以使用localStorage和sessionStorage来保存用户会话的信息，也能够实现会话跟踪。</p>
<h3 id="过滤器有哪些作用和用法？"><a href="#过滤器有哪些作用和用法？" class="headerlink" title="过滤器有哪些作用和用法？"></a>过滤器有哪些作用和用法？</h3><p> 答： Java Web开发中的过滤器（filter）是从Servlet 2.3规范开始增加的功能，并在Servlet 2.4规范中得到增强。对Web应用来说，过滤器是一个驻留在服务器端的Web组件，它可以截取客户端和服务器之间的请求与响应信息，并对这些信息进行过滤。当Web容器接受到一个对资源的请求时，它将判断是否有过滤器与这个资源相关联。如果有，那么容器将把请求交给过滤器进行处理。在过滤器中，你可以改变请求的内容，或者重新设置请求的报头信息，然后再将请求发送给目标资源。当目标资源对请求作出响应时候，容器同样会将响应先转发给过滤器，在过滤器中你可以对响应的内容进行转换，然后再将响应发送到客户端。</p>
<p>常见的过滤器用途主要包括：对用户请求进行统一认证、对用户的访问请求进行记录和审核、对用户发送的数据进行过滤或替换、转换图象格式、对响应内容进行压缩以减少传输量、对请求或响应进行加解密处理、触发资源访问事件、对XML的输出应用XSLT等。</p>
<p>和过滤器相关的接口主要有：Filter、FilterConfig和FilterChain。</p>
<p>编码过滤器的例子：</p>
<p>import java.io.IOException;</p>
<p>import javax.servlet.Filter;</p>
<p>import javax.servlet.FilterChain;</p>
<p>import javax.servlet.FilterConfig;</p>
<p>import javax.servlet.ServletException;</p>
<p>import javax.servlet.ServletRequest;</p>
<p>import javax.servlet.ServletResponse;</p>
<p>import javax.servlet.annotation.WebFilter;</p>
<p>import javax.servlet.annotation.WebInitParam;</p>
<p>@WebFilter(urlPatterns = { “*” }, </p>
<p>​        initParams = {@WebInitParam(name=”encoding”, value=”utf-8”)})</p>
<p>public class CodingFilter implements Filter {</p>
<p>​    private String defaultEncoding = “utf-8”;</p>
<p>​    @Override</p>
<p>​    public void destroy() {</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void doFilter(ServletRequest req, ServletResponse resp,</p>
<p>​            FilterChain chain) throws IOException, ServletException {</p>
<p>​        req.setCharacterEncoding(defaultEncoding);</p>
<p>​        resp.setCharacterEncoding(defaultEncoding);</p>
<p>​        chain.doFilter(req, resp);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void init(FilterConfig config) throws ServletException {</p>
<p>​        String encoding = config.getInitParameter(“encoding”);</p>
<p>​        if (encoding != null) {</p>
<p>​            defaultEncoding = encoding;</p>
<p>​        }</p>
<p>​    }</p>
<p>}</p>
<p>下载计数过滤器的例子：</p>
<p>import java.io.File;</p>
<p>import java.io.FileReader;</p>
<p>import java.io.FileWriter;</p>
<p>import java.io.IOException;</p>
<p>import java.util.Properties;</p>
<p>import java.util.concurrent.ExecutorService;</p>
<p>import java.util.concurrent.Executors;</p>
<p>import javax.servlet.Filter;</p>
<p>import javax.servlet.FilterChain;</p>
<p>import javax.servlet.FilterConfig;</p>
<p>import javax.servlet.ServletException;</p>
<p>import javax.servlet.ServletRequest;</p>
<p>import javax.servlet.ServletResponse;</p>
<p>import javax.servlet.annotation.WebFilter;</p>
<p>import javax.servlet.http.HttpServletRequest;</p>
<p>@WebFilter(urlPatterns = {“/*”})</p>
<p>public class DownloadCounterFilter implements Filter {</p>
<p>​    private ExecutorService executorService = Executors.newSingleThreadExecutor();</p>
<p>​    private Properties downloadLog;</p>
<p>​    private File logFile;</p>
<p>​    @Override</p>
<p>​    public void destroy() {</p>
<p>​        executorService.shutdown();</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void doFilter(ServletRequest req, ServletResponse resp,</p>
<p>​            FilterChain chain) throws IOException, ServletException {</p>
<p>​        HttpServletRequest request = (HttpServletRequest) req;</p>
<p>​        final String uri = request.getRequestURI();</p>
<p>​        executorService.execute(new Runnable() {</p>
<p>​            @Override</p>
<p>​            public void run() {</p>
<p>​                String value = downloadLog.getProperty(uri);</p>
<p>​                if(value == null) {</p>
<p>​                    downloadLog.setProperty(uri, “1”);</p>
<p>​                }</p>
<p>​                else {</p>
<p>​                    int count = Integer.parseInt(value);</p>
<p>​                    downloadLog.setProperty(uri, String.valueOf(++count));</p>
<p>​                }</p>
<p>​                try {</p>
<p>​                    downloadLog.store(new FileWriter(logFile), “”);</p>
<p>​                } </p>
<p>​                catch (IOException e) {</p>
<p>​                    e.printStackTrace();</p>
<p>​                }</p>
<p>​            }</p>
<p>​        });</p>
<p>​        chain.doFilter(req, resp);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void init(FilterConfig config) throws ServletException {</p>
<p>​        String appPath = config.getServletContext().getRealPath(“/“);</p>
<p>​        logFile = new File(appPath, “downloadLog.txt”);</p>
<p>​        if(!logFile.exists()) {</p>
<p>​            try {</p>
<p>​                logFile.createNewFile();</p>
<p>​            } </p>
<p>​            catch(IOException e) {</p>
<p>​                e.printStackTrace();</p>
<p>​            }</p>
<p>​        }</p>
<p>​        downloadLog = new Properties();</p>
<p>​        try {</p>
<p>​            downloadLog.load(new FileReader(logFile));</p>
<p>​        } catch (IOException e) {</p>
<p>​            e.printStackTrace();</p>
<p>​        }</p>
<p>​    }</p>
<p>}</p>
<p>说明：这里使用了Servlet 3规范中的注解来部署过滤器，当然也可以在web.xml中使用<filter>和<filter-mapping>标签部署过滤器，如108题中所示。</filter-mapping></filter></p>
<h3 id="监听器有哪些作用和用法？"><a href="#监听器有哪些作用和用法？" class="headerlink" title="监听器有哪些作用和用法？"></a>监听器有哪些作用和用法？</h3><p>答：Java Web开发中的监听器（listener）就是application、session、request三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件，如下所示：<br>①ServletContextListener：对Servlet上下文的创建和销毁进行监听。<br>②ServletContextAttributeListener：监听Servlet上下文属性的添加、删除和替换。<br>③HttpSessionListener：对Session的创建和销毁进行监听。</p>
<p>补充：session的销毁有两种情况：1). session超时（可以在web.xml中通过<session-config>/<session-timeout>标签配置超时时间）；2). 通过调用session对象的invalidate()方法使session失效。</session-timeout></session-config></p>
<p>④HttpSessionAttributeListener：对Session对象中属性的添加、删除和替换进行监听。<br>⑤ServletRequestListener：对请求对象的初始化和销毁进行监听。<br>⑥ServletRequestAttributeListener：对请求对象属性的添加、删除和替换进行监听。</p>
<p>下面是一个统计网站最多在线人数监听器的例子。</p>
<p>import javax.servlet.ServletContextEvent;</p>
<p>import javax.servlet.ServletContextListener;</p>
<p>import javax.servlet.annotation.WebListener;</p>
<p>/**</p>
<p> 上下文监听器，在服务器启动时初始化onLineCount和maxOnLineCount两个变量</p>
<p> 并将其置于服务器上下文（ServletContext）中，其初始值都是0</p>
<p>*/</p>
<p>@WebListener</p>
<p>public class InitListener implements ServletContextListener {</p>
<p>​    @Override</p>
<p>​    public void contextDestroyed(ServletContextEvent evt) {</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void contextInitialized(ServletContextEvent evt) {</p>
<p>​        evt.getServletContext().setAttribute(“onLineCount”, 0);</p>
<p>​        evt.getServletContext().setAttribute(“maxOnLineCount”, 0);</p>
<p>​    }</p>
<p>}</p>
<p>import java.text.DateFormat;</p>
<p>import java.text.SimpleDateFormat;</p>
<p>import java.util.Date;</p>
<p>import javax.servlet.ServletContext;</p>
<p>import javax.servlet.annotation.WebListener;</p>
<p>import javax.servlet.http.HttpSessionEvent;</p>
<p>import javax.servlet.http.HttpSessionListener;</p>
<p>/**</p>
<p> 会话监听器，在用户会话创建和销毁的时候根据情况</p>
<p> 修改onLineCount和maxOnLineCount的值</p>
<p>*/</p>
<p>@WebListener</p>
<p>public class MaxCountListener implements HttpSessionListener {</p>
<p>​    @Override</p>
<p>​    public void sessionCreated(HttpSessionEvent event) {</p>
<p>​        ServletContext ctx = event.getSession().getServletContext();</p>
<p>​        int count = Integer.parseInt(ctx.getAttribute(“onLineCount”).toString());</p>
<p>​        count++;</p>
<p>​        ctx.setAttribute(“onLineCount”, count);</p>
<p>​        int maxOnLineCount = Integer.parseInt(ctx.getAttribute(“maxOnLineCount”).toString());</p>
<p>​        if (count &gt; maxOnLineCount) {</p>
<p>​            ctx.setAttribute(“maxOnLineCount”, count);</p>
<p>​            DateFormat df = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);</p>
<p>​            ctx.setAttribute(“date”, df.format(new Date()));</p>
<p>​        }</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void sessionDestroyed(HttpSessionEvent event) {</p>
<p>​        ServletContext app = event.getSession().getServletContext();</p>
<p>​        int count = Integer.parseInt(app.getAttribute(“onLineCount”).toString());</p>
<p>​        count–;</p>
<p>​        app.setAttribute(“onLineCount”, count);</p>
<p>​    }</p>
<p>}</p>
<p>说明：这里使用了Servlet 3规范中的@WebListener注解配置监听器，当然你可以在web.xml文件中用<listener>标签配置监听器，如108题中所示。</listener></p>
<h3 id="web-xml文件中可以配置哪些内容？"><a href="#web-xml文件中可以配置哪些内容？" class="headerlink" title="web.xml文件中可以配置哪些内容？"></a>web.xml文件中可以配置哪些内容？</h3><p>答：web.xml用于配置Web应用的相关信息，如：监听器（listener）、过滤器（filter）、 Servlet、相关参数、会话超时时间、安全验证方式、错误页面等，下面是一些开发中常见的配置：</p>
<p>①配置Spring上下文加载监听器加载Spring配置文件并创建IoC容器：</p>
<p>  <context-param></context-param></p>
<p>​     <param-name>contextConfigLocation</param-name></p>
<p>​    <param-value>classpath:applicationContext.xml</param-value></p>
<p>  </p>
  <listener><br><br>​     <listener-class><br><br>​       org.springframework.web.context.ContextLoaderListener<br><br>​     </listener-class><br><br>  </listener>

<p>②配置Spring的OpenSessionInView过滤器来解决延迟加载和Hibernate会话关闭的矛盾：</p>
  <filter><br><br>​      <filter-name>openSessionInView</filter-name><br><br>​      <filter-class><br><br>​         org.springframework.orm.hibernate3.support.OpenSessionInViewFilter<br><br>​      </filter-class><br><br>  </filter>



<p>  <filter-mapping></filter-mapping></p>
<p>​      <filter-name>openSessionInView</filter-name></p>
<p>​      <url-pattern>/*</url-pattern></p>
<p>  </p>
<p>③配置会话超时时间为10分钟：</p>
<p>  <session-config></session-config></p>
<p>​      <session-timeout>10</session-timeout></p>
<p>  </p>
<p>④配置404和Exception的错误页面：</p>
<p>  <error-page></error-page></p>
<p>​      <error-code>404</error-code></p>
<p>​      <location>/error.jsp</location></p>
<p>  </p>
<p>  <error-page></error-page></p>
<p>​      <exception-type>java.lang.Exception</exception-type></p>
<p>​      <location>/error.jsp</location></p>
<p>  </p>
<p>⑤配置安全认证方式：</p>
<p>  <security-constraint></security-constraint></p>
<p>​      <web-resource-collection></web-resource-collection></p>
<p>​          <web-resource-name>ProtectedArea</web-resource-name></p>
<p>​          <url-pattern>/admin/*</url-pattern></p>
<p>​          <http-method>GET</http-method></p>
<p>​          <http-method>POST</http-method></p>
<p>​      </p>
<p>​      <auth-constraint></auth-constraint></p>
<p>​          <role-name>admin</role-name></p>
<p>​      </p>
<p>  </p>
<p>  <login-config></login-config></p>
<p>​      <auth-method>BASIC</auth-method></p>
<p>  </p>
<p>  <security-role></security-role></p>
<p>​      <role-name>admin</role-name></p>
<p>  </p>
<p>说明：对Servlet（小服务）、Listener（监听器）和Filter（过滤器）等Web组件的配置，Servlet 3规范提供了基于注解的配置方式，可以分别使用@WebServlet、@WebListener、@WebFilter注解进行配置。 </p>
<p>补充：如果Web提供了有价值的商业信息或者是敏感数据，那么站点的安全性就是必须考虑的问题。安全认证是实现安全性的重要手段，认证就是要解决“Are you who you say you are?”的问题。认证的方式非常多，简单说来可以分为三类：<br>A. What you know? — 口令<br>B. What you have? — 数字证书（U盾、密保卡）<br>C. Who you are? — 指纹识别、虹膜识别<br>在Tomcat中可以通过建立安全套接字层（Secure Socket Layer, SSL）以及通过基本验证或表单验证来实现对安全性的支持。</p>
<h3 id="你的项目中使用过哪些JSTL标签？"><a href="#你的项目中使用过哪些JSTL标签？" class="headerlink" title="你的项目中使用过哪些JSTL标签？"></a>你的项目中使用过哪些JSTL标签？</h3><p>答：项目中主要使用了JSTL的核心标签库，包括c:if、c:choose、&lt;c: when&gt;、&lt;c: otherwise&gt;、c:forEach等，主要用于构造循环和分支结构以控制显示逻辑。</p>
<p>说明：虽然JSTL标签库提供了core、sql、fmt、xml等标签库，但是实际开发中建议只使用核心标签库（core），而且最好只使用分支和循环标签并辅以表达式语言（EL），这样才能真正做到数据显示和业务逻辑的分离，这才是最佳实践。</p>
<h3 id="使用标签库有什么好处？如何自定义JSP标签？"><a href="#使用标签库有什么好处？如何自定义JSP标签？" class="headerlink" title="使用标签库有什么好处？如何自定义JSP标签？"></a>使用标签库有什么好处？如何自定义JSP标签？</h3><p>答：使用标签库的好处包括以下几个方面： </p>
<ul>
<li>分离JSP页面的内容和逻辑，简化了Web开发； </li>
<li>开发者可以创建自定义标签来封装业务逻辑和显示逻辑； </li>
<li>标签具有很好的可移植性、可维护性和可重用性； </li>
<li>避免了对Scriptlet（小脚本）的使用（很多公司的项目开发都不允许在JSP中书写小脚本）</li>
</ul>
<p>自定义JSP标签包括以下几个步骤： </p>
<ul>
<li>编写一个Java类实现实现Tag/BodyTag/IterationTag接口（开发中通常不直接实现这些接口而是继承TagSupport/BodyTagSupport/SimpleTagSupport类，这是对缺省适配模式的应用），重写doStartTag()、doEndTag()等方法，定义标签要完成的功能 </li>
<li>编写扩展名为tld的标签描述文件对自定义标签进行部署，tld文件通常放在WEB-INF文件夹下或其子目录中 </li>
<li>在JSP页面中使用taglib指令引用该标签库</li>
</ul>
<p>下面是一个自定义标签库的例子。</p>
<p>步骤1 - 标签类源代码TimeTag.java：</p>
<p>package com.jackfrued.tags;</p>
<p>import java.io.IOException;</p>
<p>import java.text.SimpleDateFormat;</p>
<p>import java.util.Date;</p>
<p>import javax.servlet.jsp.JspException;</p>
<p>import javax.servlet.jsp.JspWriter;</p>
<p>import javax.servlet.jsp.tagext.TagSupport;</p>
<p>public class TimeTag extends TagSupport {</p>
<p>​    private static final long serialVersionUID = 1L;</p>
<p>​    private String format = “yyyy-MM-dd hh:mm:ss”;</p>
<p>​    private String foreColor = “black”;</p>
<p>​    private String backColor = “white”;</p>
<p>​    public int doStartTag() throws JspException {</p>
<p>​         SimpleDateFormat sdf = new SimpleDateFormat(format);</p>
<p>​         JspWriter writer = pageContext.getOut();</p>
<p>​         StringBuilder sb = new StringBuilder();</p>
<p>​         sb.append(String.format(“%s”,</p>
<p>​             foreColor, backColor, sdf.format(new Date())));</p>
<p>​         try {</p>
<p>​           writer.print(sb.toString());</p>
<p>​         } catch(IOException e) {</p>
<p>​           e.printStackTrace();</p>
<p>​         }</p>
<p>​         return SKIP_BODY;</p>
<p>​      }</p>
<p>​    public void setFormat(String format) {</p>
<p>​        this.format = format;</p>
<p>​    }</p>
<p>​    public void setForeColor(String foreColor) {</p>
<p>​        this.foreColor = foreColor;</p>
<p>​    }</p>
<p>​    public void setBackColor(String backColor) {</p>
<p>​        this.backColor = backColor;</p>
<p>​    }</p>
<p>}</p>
<p>步骤2 - 编写标签库描述文件my.tld：</p>
<p>&lt;?xml version=”1.0” encoding=”UTF-8” ?&gt;</p>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" ​ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://java.sun.com/xml/ns/j2ee 

​    http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"><br><br><br><br>​    <description>定义标签库</description><br><br>​    <tlib-version>1.0</tlib-version><br><br>​    <short-name>MyTag</short-name><br><br>​    <tag><br><br>​        <name>time</name><br><br>​        <tag-class>com.jackfrued.tags.TimeTag</tag-class><br><br>​        <body-content>empty</body-content><br><br>​        <attribute><br><br>​            <name>format</name><br><br>​            <required>false</required><br><br>​        </attribute><br><br>​        <attribute><br><br>​            <name>foreColor</name><br><br>​        </attribute><br><br>​        <attribute><br><br>​            <name>backColor</name><br><br>​        </attribute><br><br>​    </tag><br><br></taglib>

<p>步骤3 - 在JSP页面中使用自定义标签：</p>
<p>&lt;%@ page pageEncoding=”UTF-8”%&gt;</p>
<p>&lt;%@ taglib prefix=”my” uri=”/WEB-INF/tld/my.tld” %&gt;</p>
<p>&lt;%</p>
<p>String path = request.getContextPath();</p>
<p>String basePath = request.getScheme() + “://“ + request.getServerName() + “:” + request.getServerPort() + path + “/“;</p>
<p>%&gt;</p>
<p>&lt;!DOCTYPE html&gt;</p>
<html><br><br>  <head><meta name="generator" content="Hexo 3.9.0"><br><br>​    <base href="<%=basePath%>"><br><br>​    <title>首页</title><br><br>    <style type="text/css"><br><br>​        * { font-family: “Arial”; font-size:72px; }<br><br>​    </style><br><br>  </head><br><br><br><br>  <body><br><br>​    &lt;my:time format=”yyyy-MM-dd” backColor=”blue” foreColor=”yellow”/&gt;<br><br>  </body><br><br></html>



<p>提示：如果要将自定义的标签库发布成JAR文件，需要将标签库描述文件（tld文件）放在JAR文件的META-INF目录下，可以JDK中的jar工具完成JAR文件的生成，如果不清楚如何操作，可以请教谷老师和百老师。</p>
<h3 id="说一下表达式语言（EL）的隐式对象及其作用。"><a href="#说一下表达式语言（EL）的隐式对象及其作用。" class="headerlink" title="说一下表达式语言（EL）的隐式对象及其作用。"></a>说一下表达式语言（EL）的隐式对象及其作用。</h3><p> 答：EL的隐式对象包括：pageContext、initParam（访问上下文参数）、param（访问请求参数）、paramValues、header（访问请求头）、headerValues、cookie（访问cookie）、applicationScope（访问application作用域）、sessionScope（访问session作用域）、requestScope（访问request作用域）、pageScope（访问page作用域）。</p>
<p>用法如下所示：</p>
<p>${pageContext.request.method}</p>
<p>${pageContext”request”}</p>
<p>${pageContext.request[“method”]}</p>
<p>${pageContext[“request”].method}</p>
<p>${initParam.defaultEncoding}</p>
<p>${header[“accept-language”]}</p>
<p>${headerValues”accept-language”}</p>
<p>${cookie.jsessionid.value}</p>
<p>${sessionScope.loginUser.username}</p>
<p>补充：表达式语言的.和[]运算作用是一致的，唯一的差别在于如果访问的属性名不符合Java标识符命名规则，例如上面的accept-language就不是一个有效的Java标识符，那么这时候就只能用[]运算符而不能使用.运算符获取它的值</p>
<h3 id="表达式语言（EL）支持哪些运算符？"><a href="#表达式语言（EL）支持哪些运算符？" class="headerlink" title="表达式语言（EL）支持哪些运算符？"></a>表达式语言（EL）支持哪些运算符？</h3><p>答：除了.和[]运算符，EL还提供了： </p>
<ul>
<li>算术运算符：+、-、*、/或div、%或mod </li>
<li>关系运算符：==或eq、!=或ne、&gt;或gt、&gt;=或ge、&lt;或lt、&lt;=或le </li>
<li>逻辑运算符：&amp;&amp;或and、||或or、!或not </li>
<li>条件运算符：${statement? A : B}（跟Java的条件运算符类似） </li>
<li>empty运算符：检查一个值是否为null或者空（数组长度为0或集合中没有元素也返回true）</li>
</ul>
<h3 id="Java-Web开发的Model-1和Model-2分别指的是什么？"><a href="#Java-Web开发的Model-1和Model-2分别指的是什么？" class="headerlink" title="Java Web开发的Model 1和Model 2分别指的是什么？"></a>Java Web开发的Model 1和Model 2分别指的是什么？</h3><p>答：Model 1是以页面为中心的Java Web开发，使用JSP+JavaBean技术将页面显示逻辑和业务逻辑处理分开，JSP实现页面显示，JavaBean对象用来保存数据和实现业务逻辑。Model 2是基于MVC（模型-视图-控制器，Model-View-Controller）架构模式的开发模型，实现了模型和视图的彻底分离，利于团队开发和代码复用，如下图所示。</p>
<h3 id="Servlet-3中的异步处理指的是什么？"><a href="#Servlet-3中的异步处理指的是什么？" class="headerlink" title="Servlet 3中的异步处理指的是什么？"></a>Servlet 3中的异步处理指的是什么？</h3><p>答：在Servlet 3中引入了一项新的技术可以让Servlet异步处理请求。有人可能会质疑，既然都有多线程了，还需要异步处理请求吗？答案是肯定的，因为如果一个任务处理时间相当长，那么Servlet或Filter会一直占用着请求处理线程直到任务结束，随着并发用户的增加，容器将会遭遇线程超出的风险，这这种情况下很多的请求将会被堆积起来而后续的请求可能会遭遇拒绝服务，直到有资源可以处理请求为止。异步特性可以帮助应用节省容器中的线程，特别适合执行时间长而且用户需要得到结果的任务，如果用户不需要得到结果则直接将一个Runnable对象交给Executor并立即返回即可。（如果不清楚多线程和线程池的相关内容，请查看《Java面试题全集（上）》关于多线程和线程池的部分或阅读我的另一篇文章《关于Java并发编程的总结和思考》）</p>
<p>补充：多线程在Java诞生初期无疑是一个亮点，而Servlet单实例多线程的工作方式也曾为其赢得美名，然而技术的发展往往会颠覆我们很多的认知，就如同当年爱因斯坦的相对论颠覆了牛顿的经典力学一般。事实上，异步处理绝不是Serlvet 3首创，如果你了解Node.js的话，对Servlet 3的这个重要改进就不以为奇了。</p>
<p>下面是一个支持异步处理请求的Servlet的例子。</p>
<p>import java.io.IOException;</p>
<p>import javax.servlet.AsyncContext;</p>
<p>import javax.servlet.ServletException;</p>
<p>import javax.servlet.annotation.WebServlet;</p>
<p>import javax.servlet.http.HttpServlet;</p>
<p>import javax.servlet.http.HttpServletRequest;</p>
<p>import javax.servlet.http.HttpServletResponse;</p>
<p>@WebServlet(urlPatterns = {“/async”}, asyncSupported = true)</p>
<p>public class AsyncServlet extends HttpServlet {</p>
<p>​    private static final long serialVersionUID = 1L;</p>
<p>​    @Override</p>
<p>​    public void doGet(HttpServletRequest req, HttpServletResponse resp) </p>
<p>​            throws ServletException, IOException {</p>
<p>​        // 开启Tomcat异步Servlet支持</p>
<p>​        req.setAttribute(“org.apache.catalina.ASYNC_SUPPORTED”, true);</p>
<p>​        final AsyncContext ctx = req.startAsync();  // 启动异步处理的上下文</p>
<p>​        // ctx.setTimeout(30000);</p>
<p>​        ctx.start(new Runnable() {</p>
<p>​            @Override</p>
<p>​            public void run() {</p>
<p>​                // 在此处添加异步处理的代码</p>
<p>​                ctx.complete();</p>
<p>​            }</p>
<p>​        });</p>
<p>​    }</p>
<p>}</p>
<h3 id="讲解JSP中的四种作用域。"><a href="#讲解JSP中的四种作用域。" class="headerlink" title="讲解JSP中的四种作用域。"></a>讲解JSP中的四种作用域。</h3><p>答：JSP中的四种作用域包括page、request、session和application，具体来说： </p>
<ul>
<li>page代表与一个页面相关的对象和属性。 </li>
<li>request代表与Web客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面，涉及多个Web组件；需要在页面显示的临时数据可以置于此作用域。 </li>
<li>session代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的session中。 </li>
<li>application代表与整个Web应用程序相关的对象和属性，它实质上是跨越整个Web应用程序，包括多个页面、请求和会话的一个全局作用域。</li>
</ul>
<h3 id="如何在基于Java的Web项目中实现文件上传和下载？"><a href="#如何在基于Java的Web项目中实现文件上传和下载？" class="headerlink" title="如何在基于Java的Web项目中实现文件上传和下载？"></a>如何在基于Java的Web项目中实现文件上传和下载？</h3><p>答：在Sevlet 3 以前，Servlet API中没有支持上传功能的API，因此要实现上传功能需要引入第三方工具从POST请求中获得上传的附件或者通过自行处理输入流来获得上传的文件，我们推荐使用Apache的commons-fileupload。<br>从Servlet 3开始，文件上传变得无比简单，相信看看下面的例子一切都清楚了。</p>
<p>上传页面index.jsp：</p>
<p>&lt;%@ page pageEncoding=”utf-8”%&gt;</p>
<p>&lt;!DOCTYPE html&gt;</p>
<html><br><br><head><meta name="generator" content="Hexo 3.9.0"><br><br><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><br><br><title>Photo Upload</title><br><br></head><br><br><body><br><br><h1>Select your photo and upload</h1><br><br><hr><br><br><div style="color:red;font-size:14px;">${hint}</div><br><br><form action="UploadServlet" method="post" enctype="multipart/form-data"><br><br>​    Photo file: <input type="file" name="photo"><br><br>​    <input type="submit" value="Upload"><br><br></form><br><br></body><br><br></html>

<p>支持上传的Servlet：</p>
<p>package com.jackfrued.servlet;</p>
<p>import java.io.IOException;</p>
<p>import javax.servlet.ServletException;</p>
<p>import javax.servlet.annotation.MultipartConfig;</p>
<p>import javax.servlet.annotation.WebServlet;</p>
<p>import javax.servlet.http.HttpServlet;</p>
<p>import javax.servlet.http.HttpServletRequest;</p>
<p>import javax.servlet.http.HttpServletResponse;</p>
<p>import javax.servlet.http.Part;</p>
<p>@WebServlet(“/UploadServlet”)</p>
<p>@MultipartConfig</p>
<p>public class UploadServlet extends HttpServlet {</p>
<p>​    private static final long serialVersionUID = 1L;</p>
<p>​    protected void doPost(HttpServletRequest request,</p>
<p>​            HttpServletResponse response) throws ServletException, IOException {</p>
<p>​        // 可以用request.getPart()方法获得名为photo的上传附件</p>
<p>​        // 也可以用request.getParts()获得所有上传附件（多文件上传）</p>
<p>​        // 然后通过循环分别处理每一个上传的文件</p>
<p>​        Part part = request.getPart(“photo”);</p>
<p>​        if (part != null &amp;&amp; part.getSubmittedFileName().length() &gt; 0) {</p>
<p>​            // 用ServletContext对象的getRealPath()方法获得上传文件夹的绝对路径</p>
<p>​            String savePath = request.getServletContext().getRealPath(“/upload”);</p>
<p>​            // Servlet 3.1规范中可以用Part对象的getSubmittedFileName()方法获得上传的文件名</p>
<p>​            // 更好的做法是为上传的文件进行重命名（避免同名文件的相互覆盖）</p>
<p>​            part.write(savePath + “/“ + part.getSubmittedFileName());</p>
<p>​            request.setAttribute(“hint”, “Upload Successfully!”);</p>
<p>​        } else {</p>
<p>​            request.setAttribute(“hint”, “Upload failed!”);</p>
<p>​        }</p>
<p>​        // 跳转回到上传页面</p>
<p>​        request.getRequestDispatcher(“index.jsp”).forward(request, response);</p>
<p>​    }</p>
<p>}</p>
<h3 id="服务器收到用户提交的表单数据，到底是调用Servlet的doGet-还是doPost-方法？"><a href="#服务器收到用户提交的表单数据，到底是调用Servlet的doGet-还是doPost-方法？" class="headerlink" title="服务器收到用户提交的表单数据，到底是调用Servlet的doGet()还是doPost()方法？"></a>服务器收到用户提交的表单数据，到底是调用Servlet的doGet()还是doPost()方法？</h3><p> 答：HTML的<form>元素有一个method属性，用来指定提交表单的方式，其值可以是get或post。我们自定义的Servlet一般情况下会重写doGet()或doPost()两个方法之一或全部，如果是GET请求就调用doGet()方法，如果是POST请求就调用doPost()方法，那为什么为什么这样呢？我们自定义的Servlet通常继承自HttpServlet，HttpServlet继承自GenericServlet并重写了其中的service()方法，这个方法是Servlet接口中定义的。HttpServlet重写的service()方法会先获取用户请求的方法，然后根据请求方法调用doGet()、doPost()、doPut()、doDelete()等方法，如果在自定义Servlet中重写了这些方法，那么显然会调用重写过的（自定义的）方法，这显然是对模板方法模式的应用（如果不理解，请参考阎宏博士的《Java与模式》一书的第37章）。当然，自定义Servlet中也可以直接重写service()方法，那么不管是哪种方式的请求，都可以通过自己的代码进行处理，这对于不区分请求方法的场景比较合适。</form></p>
<p>117、JSP中的静态包含和动态包含有什么区别？<br>答：静态包含是通过JSP的include指令包含页面，动态包含是通过JSP标准动作jsp:forward包含页面。静态包含是编译时包含，如果包含的页面不存在则会产生编译错误，而且两个页面的”contentType”属性应保持一致，因为两个页面会合二为一，只产生一个class文件，因此被包含页面发生的变动再包含它的页面更新前不会得到更新。动态包含是运行时包含，可以向被包含的页面传递参数，包含页面和被包含页面是独立的，会编译出两个class文件，如果被包含的页面不存在，不会产生编译错误，也不影响页面其他部分的执行。代码如下所示：</p>
<p>&lt;%– 静态包含 –%&gt;</p>
<p>&lt;%@ include file=”…” %&gt;</p>
<p>&lt;%– 动态包含 –%&gt;</p>
<p>&lt;jsp:include page=”…”&gt;</p>
<p>​    &lt;jsp:param name=”…” value=”…” /&gt;</p>
<p>/jsp:include</p>
<h3 id="Servlet中如何获取用户提交的查询参数或表单数据？"><a href="#Servlet中如何获取用户提交的查询参数或表单数据？" class="headerlink" title="Servlet中如何获取用户提交的查询参数或表单数据？"></a>Servlet中如何获取用户提交的查询参数或表单数据？</h3><p>答：可以通过请求对象（HttpServletRequest）的getParameter()方法通过参数名获得参数值。如果有包含多个值的参数（例如复选框），可以通过请求对象的getParameterValues()方法获得。当然也可以通过请求对象的getParameterMap()获得一个参数名和参数值的映射（Map）。</p>
<p>119、Servlet中如何获取用户配置的初始化参数以及服务器上下文参数？<br>答：可以通过重写Servlet接口的init(ServletConfig)方法并通过ServletConfig对象的getInitParameter()方法来获取Servlet的初始化参数。可以通过ServletConfig对象的getServletContext()方法获取ServletContext对象，并通过该对象的getInitParameter()方法来获取服务器上下文参数。当然，ServletContext对象也在处理用户请求的方法（如doGet()方法）中通过请求对象的getServletContext()方法来获得。</p>
<h3 id="如何设置请求的编码以及响应内容的类型？"><a href="#如何设置请求的编码以及响应内容的类型？" class="headerlink" title="如何设置请求的编码以及响应内容的类型？"></a>如何设置请求的编码以及响应内容的类型？</h3><p>答：通过请求对象（ServletRequest）的setCharacterEncoding(String)方法可以设置请求的编码，其实要彻底解决乱码问题就应该让页面、服务器、请求和响应、Java程序都使用统一的编码，最好的选择当然是UTF-8；通过响应对象（ServletResponse）的setContentType(String)方法可以设置响应内容的类型，当然也可以通过HttpServletResponsed对象的setHeader(String, String)方法来设置。</p>
<p>说明：现在如果还有公司在面试的时候问JSP的声明标记、表达式标记、小脚本标记这些内容的话，这样的公司也不用去了，其实JSP内置对象、JSP指令这些东西基本上都可以忘却了，关于Java Web开发的相关知识，可以看一下我的《Servlet&amp;JSP思维导图》，上面有完整的知识点的罗列。想了解如何实现自定义MVC框架的，可以看一下我的《Java Web自定义MVC框架详解》。</p>
<h3 id="阐述Servlet和CGI的区别"><a href="#阐述Servlet和CGI的区别" class="headerlink" title="阐述Servlet和CGI的区别?"></a>阐述Servlet和CGI的区别?</h3><p>答：Servlet与CGI的区别在于Servlet处于服务器进程中，它通过多线程方式运行其service()方法，一个实例可以服务于多个请求，并且其实例一般不会销毁，而CGI对每个请求都产生新的进程，服务完成后就销毁，所以效率上低于Servlet。</p>
<p>补充：Sun Microsystems公司在1996年发布Servlet技术就是为了和CGI进行竞争，Servlet是一个特殊的Java程序，一个基于Java的Web应用通常包含一个或多个Servlet类。Servlet不能够自行创建并执行，它是在Servlet容器中运行的，容器将用户的请求传递给Servlet程序，并将Servlet的响应回传给用户。通常一个Servlet会关联一个或多个JSP页面。以前CGI经常因为性能开销上的问题被诟病，然而Fast CGI早就已经解决了CGI效率上的问题，所以面试的时候大可不必信口开河的诟病CGI，事实上有很多你熟悉的网站都使用了CGI技术。</p>
<h3 id="什么是Servlet？"><a href="#什么是Servlet？" class="headerlink" title="什么是Servlet？"></a>什么是Servlet？</h3><p>Servlet是用来处理客户端请求并产生动态网页内容的Java类。Servlet主要是用来处理或者是存储HTML表单提交的数据，产生动态内容，在无状态的HTTP协议下管理状态信息。</p>
<h3 id="Servlet接口中有哪些方法？"><a href="#Servlet接口中有哪些方法？" class="headerlink" title="Servlet接口中有哪些方法？"></a>Servlet接口中有哪些方法？</h3><p>答：Servlet接口定义了5个方法，其中前三个方法与Servlet生命周期相关： </p>
<ul>
<li>void init(ServletConfig config) throws ServletException </li>
<li>void service(ServletRequest req, ServletResponse resp) throws ServletException, java.io.IOException </li>
<li>void destory() </li>
<li>java.lang.String getServletInfo() </li>
<li>ServletConfig getServletConfig()</li>
</ul>
<p>Web容器加载Servlet并将其实例化后，Servlet生命周期开始，容器运行其init()方法进行Servlet的初始化；请求到达时调用Servlet的service()方法，service()方法会根据需要调用与请求对应的doGet或doPost等方法；当服务器关闭或项目被卸载时服务器会将Servlet实例销毁，此时会调用Servlet的destroy()方法。</p>
<h3 id="说一下Servlet的体系结构。"><a href="#说一下Servlet的体系结构。" class="headerlink" title="说一下Servlet的体系结构。"></a>说一下Servlet的体系结构。</h3><p>所有的Servlet都必须要实现的核心的接口是javax.servlet.Servlet。每一个Servlet都必须要直接或者是间接实现这个接口，或者是继承javax.servlet.GenericServlet或者javax.servlet.http.HTTPServlet。最后，Servlet使用多线程可以并行的为多个请求服务。</p>
<h3 id="Applet和Servlet有什么区别？"><a href="#Applet和Servlet有什么区别？" class="headerlink" title="Applet和Servlet有什么区别？"></a>Applet和Servlet有什么区别？</h3><p>Applet是运行在客户端主机的浏览器上的客户端Java程序。而Servlet是运行在web服务器上的服务端的组件。applet可以使用用户界面类，而Servlet没有用户界面，相反，Servlet是等待客户端的HTTP请求，然后为请求产生响应。</p>
<h3 id="GenericServlet和HttpServlet有什么区别？"><a href="#GenericServlet和HttpServlet有什么区别？" class="headerlink" title="GenericServlet和HttpServlet有什么区别？"></a>GenericServlet和HttpServlet有什么区别？</h3><p>GenericServlet类实现了Servlet和ServletConfig接口。实现了除了service()之外的其他方法，在创建Servlet对象时，可以继承GenericServlet类来简化程序的代码，但需要实现service()方法。</p>
<p>HttpServlet类继承了GeneriServlet类，为实际开发中大多数用Servlet处理 HTTP请求的应用灵活的方法。</p>
<h3 id="解释下Servlet的生命周期。"><a href="#解释下Servlet的生命周期。" class="headerlink" title="解释下Servlet的生命周期。"></a>解释下Servlet的生命周期。</h3><p>对每一个客户端的请求，Servlet引擎载入Servlet，调用它的init()方法，完成Servlet的初始化。然后，Servlet对象通过为每一个请求单独调用service()方法来处理所有随后来自客户端的请求，最后，调用Servlet(译者注：这里应该是Servlet而不是server)的destroy()方法把Servlet删除掉。</p>
<h3 id="doGet-方法和doPost-方法有什么区别？"><a href="#doGet-方法和doPost-方法有什么区别？" class="headerlink" title="doGet()方法和doPost()方法有什么区别？"></a>doGet()方法和doPost()方法有什么区别？</h3><p>doGet：GET方法会把名值对追加在请求的URL后面。因为URL对字符数目有限制，进而限制了用在客户端请求的参数值的数目。并且请求中的参数值是可见的，因此，敏感信息不能用这种方式传递。</p>
<p>doPOST：POST方法通过把请求参数值放在请求体中来克服GET方法的限制，因此，可以发送的参数的数目是没有限制的。最后，通过POST请求传递的敏感信息对外部客户端是不可见的。</p>
<h3 id="什么是Web应用程序？"><a href="#什么是Web应用程序？" class="headerlink" title="什么是Web应用程序？"></a>什么是Web应用程序？</h3><p>Web应用程序是对Web或者是应用服务器的动态扩展。有两种类型的Web应用：面向表现的和面向服务的。面向表现的Web应用程序会产生包含了很多种标记语言和动态内容的交互的web页面作为对请求的响应。而面向服务的Web应用实现了Web服务的端点(endpoint)。一般来说，一个Web应用可以看成是一组安装在服务器URL名称空间的特定子集下面的Servlet的集合。</p>
<h3 id="什么是服务端包含-Server-Side-Include-？"><a href="#什么是服务端包含-Server-Side-Include-？" class="headerlink" title="什么是服务端包含(Server Side Include)？"></a>什么是服务端包含(Server Side Include)？</h3><p>服务端包含(SSI)是一种简单的解释型服务端脚本语言，大多数时候仅用在Web上，用servlet标签嵌入进来。SSI最常用的场景把一个或多个文件包含到Web服务器的一个Web页面中。当浏览器访问Web页面的时候，Web服务器会用对应的servlet产生的文本来替换Web页面中的servlet标签。</p>
<h3 id="什么是Servlet链-Servlet-Chaining-？"><a href="#什么是Servlet链-Servlet-Chaining-？" class="headerlink" title="什么是Servlet链(Servlet Chaining)？"></a>什么是Servlet链(Servlet Chaining)？</h3><p>Servlet链是把一个Servlet的输出发送给另一个Servlet的方法。第二个Servlet的输出可以发送给第三个Servlet，依次类推。链条上最后一个Servlet负责把响应发送给客户端。</p>
<h3 id="如何知道是哪一个客户端的机器正在请求你的Servlet？"><a href="#如何知道是哪一个客户端的机器正在请求你的Servlet？" class="headerlink" title="如何知道是哪一个客户端的机器正在请求你的Servlet？"></a>如何知道是哪一个客户端的机器正在请求你的Servlet？</h3><p>ServletRequest类可以找出客户端机器的IP地址或者是主机名。getRemoteAddr()方法获取客户端主机的IP地址，getRemoteHost()可以获取主机名。看下这里的例子。</p>
<h3 id="HTTP响应的结构是怎么样的？"><a href="#HTTP响应的结构是怎么样的？" class="headerlink" title="HTTP响应的结构是怎么样的？"></a>HTTP响应的结构是怎么样的？</h3><p>HTTP响应由三个部分组成：</p>
<p>状态码(Status Code)：描述了响应的状态。可以用来检查是否成功的完成了请求。请求失败的情况下，状态码可用来找出失败的原因。如果Servlet没有返回状态码，默认会返回成功的状态码HttpServletResponse.SC_OK。</p>
<p>HTTP头部(HTTP Header)：它们包含了更多关于响应的信息。比如：头部可以指定认为响应过期的过期日期，或者是指定用来给用户安全的传输实体内容的编码格式。如何在Serlet中检索HTTP的头部看这里。</p>
<p>主体(Body)：它包含了响应的内容。它可以包含HTML代码，图片，等等。主体是由传输在HTTP消息中紧跟在头部后面的数据字节组成的。</p>
<h3 id="什么是cookie？session和cookie有什么区别？"><a href="#什么是cookie？session和cookie有什么区别？" class="headerlink" title="什么是cookie？session和cookie有什么区别？"></a>什么是cookie？session和cookie有什么区别？</h3><p>cookie是Web服务器发送给浏览器的一块信息。浏览器会在本地文件中给每一个Web服务器存储cookie。以后浏览器在给特定的Web服务器发请求的时候，同时会发送所有为该服务器存储的cookie。下面列出了session和cookie的区别：</p>
<p>无论客户端浏览器做怎么样的设置，session都应该能正常工作。客户端可以选择禁用cookie，但是，session仍然是能够工作的，因为客户端无法禁用服务端的session。</p>
<p>在存储的数据量方面session和cookies也是不一样的。session能够存储任意的Java对象，cookie只能存储String类型的对象。</p>
<h3 id="浏览器和Servlet通信使用的是什么协议？"><a href="#浏览器和Servlet通信使用的是什么协议？" class="headerlink" title="浏览器和Servlet通信使用的是什么协议？"></a>浏览器和Servlet通信使用的是什么协议？</h3><p>浏览器和Servlet通信使用的是HTTP协议。</p>
<h3 id="什么是HTTP隧道？"><a href="#什么是HTTP隧道？" class="headerlink" title="什么是HTTP隧道？"></a>什么是HTTP隧道？</h3><p>HTTP隧道是一种利用HTTP或者是HTTPS把多种网络协议封装起来进行通信的技术。因此，HTTP协议扮演了一个打通用于通信的网络协议的管道的包装器的角色。把其他协议的请求掩盖成HTTP的请求就是HTTP隧道。</p>
<h3 id="sendRedirect-和forward-方法有什么区别？"><a href="#sendRedirect-和forward-方法有什么区别？" class="headerlink" title="sendRedirect()和forward()方法有什么区别？"></a>sendRedirect()和forward()方法有什么区别？</h3><p>sendRedirect()方法会创建一个新的请求，而forward()方法只是把请求转发到一个新的目标上。重定向(redirect)以后，之前请求作用域范围以内的对象就失效了，因为会产生一个新的请求，而转发(forwarding)以后，之前请求作用域范围以内的对象还是能访问的。一般认为sendRedirect()比forward()要慢。</p>
<h3 id="什么是URL编码和URL解码？"><a href="#什么是URL编码和URL解码？" class="headerlink" title="什么是URL编码和URL解码？"></a>什么是URL编码和URL解码？</h3><p>URL编码是负责把URL里面的空格和其他的特殊字符替换成对应的十六进制表示，反之就是解码。</p>
<h3 id="转发（forward）和重定向（redirect）的区别？"><a href="#转发（forward）和重定向（redirect）的区别？" class="headerlink" title="转发（forward）和重定向（redirect）的区别？"></a>转发（forward）和重定向（redirect）的区别？</h3><p>答：forward是容器中控制权的转向，是服务器请求资源，服务器直接访问目标地址的URL，把那个URL 的响应内容读取过来，然后把这些内容再发给浏览器，浏览器根本不知道服务器发送的内容是从哪儿来的，所以它的地址栏中还是原来的地址。redirect就是服务器端根据逻辑，发送一个状态码，告诉浏览器重新去请求那个地址，因此从浏览器的地址栏中可以看到跳转后的链接地址，很明显redirect无法访问到服务器保护起来资源，但是可以从一个网站redirect到其他网站。forward更加高效，所以在满足需要时尽量使用forward（通过调用RequestDispatcher对象的forward()方法，该对象可以通过ServletRequest对象的getRequestDispatcher()方法获得），并且这样也有助于隐藏实际的链接；在有些情况下，比如需要访问一个其它服务器上的资源，则必须使用重定向（通过HttpServletResponse对象调用其sendRedirect()方法实现）。</p>

  	</div>
	  
	  <div class="article-tags tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
		
	
		<div class="art-item-footer">
				
					<span class="art-item-left"><i class="icon icon-chevron-thin-left"></i>prev：<a href="/2018/10/20/Java-面试题系列篇-概念解释/" rel="prev"  title="Java 面试题系列篇-概念解释">
						Java 面试题系列篇-概念解释 
					</a></span>
				
				
					<span class="art-item-right">next：<a href="/2018/10/20/Java-面试题系列篇-序列化相关/" rel="next"  title="Java 面试题系列篇-序列化相关">
						Java 面试题系列篇-序列化相关
					</a><i class="icon icon-chevron-thin-right"></i></span>
				
		</div>
	
	</section>
	
</article>
<script>
	window.subData = {
		title: 'Java 面试题系列篇-JSP和servlet',
		tools: true
	}
</script>

      </div>
      <aside class='l_side'>
        
  <section class='m_widget links'>
<div class='header'>Links</div>
<div class='content'>
    <ul class="entry">
    
        <li><a class="flat-box" target="_blank" href="https://iiong.com/">
            <div class='name'>淮城一只猫</div>
        </a></li>
    
    </ul>
</div>
</section>

  <section class='m_widget categories'>
<div class='header'>Categories</div>
<div class='content'>
    
    <ul class="entry">
    
        <li><a class="flat-box" href="/categories/Android基础/"><div class='name'>Android基础</div><div class='badget'>1</div></a></li>
    
    </ul>
    
</div>
</section>

  
<div class="m_widget tagcloud">
    <div class="header">Tags</div>
    <div class='content'>
        <a href="/tags/Android/" style="font-size: 14px; color: #808080">Android</a> <a href="/tags/HTML/" style="font-size: 14px; color: #808080">HTML</a> <a href="/tags/Java/" style="font-size: 20px; color: #000">Java</a> <a href="/tags/Python/" style="font-size: 14px; color: #808080">Python</a>
    </div>
</div>



      </aside>
      <script>setLoadingBarProgress(60);</script>
    </div>
  </div>
  <footer id="footer" class="clearfix">

	<div class="social-wrapper">
  	
      
        <a href="https://github.com/stkevintan" class="social github"
          target="_blank" rel="external">
          <span class="icon icon-github"></span>
        </a>
      
        <a href="https://twitter.com/kevinsfork" class="social twitter"
          target="_blank" rel="external">
          <span class="icon icon-twitter"></span>
        </a>
      
        <a href="/atom.xml" class="social rss"
          target="_blank" rel="external">
          <span class="icon icon-rss"></span>
        </a>
      
    
  </div>
  
  <div>Theme <a href='https://github.com/stkevintan/hexo-theme-material-flow' class="codename">MaterialFlow</a> designed by <a href="http://keyin.me/" target="_blank">Kevin Tan</a>.</div>
  
</footer>


  <script>setLoadingBarProgress(80);</script>
  

<script src="//apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src='//cdn.bootcss.com/node-waves/0.7.5/waves.min.js'></script>
<script src="//cdn.bootcss.com/scrollReveal.js/3.3.2/scrollreveal.min.js"></script>
<script src="/js/jquery.fitvids.js"></script>
<script>
	var GOOGLE_CUSTOM_SEARCH_API_KEY = "";
	var GOOGLE_CUSTOM_SEARCH_ENGINE_ID = "";
	var ALGOLIA_API_KEY = "";
	var ALGOLIA_APP_ID = "";
	var ALGOLIA_INDEX_NAME = "";
  var AZURE_SERVICE_NAME = "";
  var AZURE_INDEX_NAME = "";
  var AZURE_QUERY_KEY = "";
  var BAIDU_API_ID = "";
  var SEARCH_SERVICE = "hexo";
  var ROOT = "/"||"/";
  if(!ROOT.endsWith('/'))ROOT += '/';
</script>
<script src="/js/search.js"></script>
<script src="/js/app.js"></script>


  <script>setLoadingBarProgress(100);</script>
</body>
</html>
